# sL3_Simple_Demo.tcl
   #
   # Sets up a single stream on each of two cards.  Card iSlot is connected
   # to a router port 10.1.1.1 and has a stream IP of 10.1.1.10 and a MAC address
   # of 00 00 00 00 00 01.  Card iSlot2 is connected to a router port of 10.2.1.1
   # with a stream IP of 10.2.1.10 with a MAC address of 00 00 00 00 00 02.
   #
   # We set the router port (gateway) IP in the stream so we dont need to set 
   # the L3 address parameters.
   #
   # We arp for the router MAC then transmit a single burst from card 1 to card 2
   # and display the capture data.
   #
   # ASSUMES:
   # smartlib.tcl has been sourced before sourcing this program
   # Requires Tcl version 8.x or higher
   ########################################################################
   
   set iHub 0
   set iSlot 0
   set iPort 0
   
   set iHub2 0
   set iSlot2 1
   set iPort2 0
   
   set burstCount 5
   
   # total streams is one plus STREAMS2ADD
   set SOURCE_STREAM 1
   set STREAMS2ADD 4
   set DATA_LENGTH 96
   
        ###############################################################
        ##################   PROCEDURES  ##############################
        ###############################################################
   
   ######################################################################
   # LIBCMD error handler 
   ######################################################################
   proc LIBCMD {args} {
        set iResponse [uplevel $args]
        if {$iResponse < 0} {
           puts "$args :  $iResponse"
        }
   }
   #####################################################################
   
   #####################################################################
   # wait_for_input
   # Pause routine that allows user to view error messages
   #####################################################################
   proc wait_for_input {} {
   
      puts "Press ENTER to continue"
      gets stdin response
      return $response
   }
   #####################################################################
   
   #####################################################################
   # reset_capture   start capture
   #####################################################################
   proc reset_capture { H S P } {
   
   LIBCMD HTSetCommand $::L3_CAPTURE_OFF_TYPE 0 0 0 "" $H $S $P
   LIBCMD HTSetCommand $::L3_CAPTURE_ALL_TYPE 0 0 0 "" $H $S $P
   }
   #####################################################################
   
   #####################################################################
   proc display_count {H S P} {
   
      struct_new cs HTCountStructure
   
      # do a priming read and wait 1/2 second
      HTGetCounters cs $H $S $P
      after 500
      # wait while we are still sending or receiving packets
      while { ($cs(RcvPktRate) !=0) || ($cs(TmtPktRate) !=0) } {
         after 100
         LIBCMD HTGetCounters cs  $H $S $P
       } 
       # wait another 1/2 second and take final read
       after 500
       LIBCMD HTGetCounters cs  $H $S $P
   
       ######################
       # Display counts
       ######################
       puts "--------------------------------------"
       puts "        Test Results"
       puts "--------------------------------------"
       puts "                 Card [expr $S + 1]     "
       puts "--------------------------------------"
       puts "Tx Packets      $cs(TmtPkt)          "
       puts "Rx Packets      $cs(RcvPkt)          "
       puts "Collisions     $cs(Collision)          "
       puts "Recvd Trigger     $cs(RcvTrig)          "
       puts "CRC Errors     $cs(CRC)          "
       puts "--------------------------------------"
       puts "Oversize      $cs(Oversize)           "
       puts "Undersize     $cs(Undersize)           "
       puts "--------------------------------------"
   }
   
   ###############################################################
   
   #####################################################################
   proc display_capture {H S P {output stdout} } {
      struct_new CapCount Layer3CaptureCountInfo
      ##################################
      # First get the number of packets
      # in the capture buffer
      # If there arent any, display an
      # error and exit
      ##################################
      LIBCMD HTGetStructure $::L3_CAPTURE_COUNT_INFO 0 0 0 CapCount 0 $H $S $P
      if {$CapCount(ulCount) < 1} {
          puts $output "No packets captured on card [expr $S + 1]"
      } else {
          ####################################
          # We have packets to display
          # Display count and create structure
          # for data
          #################################### 
          puts $output "Displaying $CapCount(ulCount) packets captured on card [expr $S + 1]"
          struct_new CapData Layer3CaptureData
          #################################
          # from first to as many packets
          # as there are on the card
          #################################
          for {set i 0} {$i < $CapCount(ulCount)} {incr i} {
             LIBCMD HTGetStructure $::L3_CAPTURE_PACKET_DATA_INFO $i 0 0 CapData 0 $H $S $P
             # display packet number
             puts $output ""   
             puts $output "-----------------------"
             puts $output "PACKET $i "
             puts $output "-----------------------"
             ################################################
             # from the first byte to the end of tha packet
             ################################################
             for {set j 0} {$j < $CapData(uiLength)} {incr j} {
                ######################################
                # put a newline every 16 bytes
                ######################################
                if {[expr $j % 16] == 0} {
                   puts $output ""
                   ##################################
                   # put bute number in first column
                   ##################################
                   puts -nonewline $output [format "%4i:   " $j]
                }
                   ##################################
                   # put a space then the byte in hex
                   # with two spaces with leading zero
                   # note _ubyte_  usage
                   ##################################
                   puts -nonewline $output " "
                   puts -nonewline $output [format "%02X" $CapData(cData.$j._ubyte_)]              
             }
          #########################
            # If were sending to the
             # screen, give the user
             # a chance to quit
             #########################
             puts $output "\n"
             if {$output == "stdout"} {
                puts "Press ENTER key to continue, Q to quit"
                gets stdin response
                if {$response == "Q" || $response == "q"} {
                break
             }
             }
         }
      }
   }
   #########################################################################
   
   ##########################################################################
   proc display_streams { H S P {streams 5} {output stdout} } {
   
     global L3_DEFINED_STREAM_COUNT_INFO L3_STREAM_INFO
   
   
       #####################################
       # Check for number of streams       #
       # using L3_DEFINED_STREAM_COUNT_INFO#
       # This program only sets up only one#
       # stream.                           #
       # There is one non-transmitting     #
       # stream always on the card         #
       # used to hold card data so the     #
       # count of transmitting streams will#
       # always be one less than the total #
       # reported.                         #
       #####################################
       struct_new DefStreams ULong
       LIBCMD HTGetStructure $L3_DEFINED_STREAM_COUNT_INFO 0 0 0 DefStreams 0 $H $S $P
       if { $DefStreams(ul)  < 2 } {
          puts $output "No transmitting streams on card [expr $S +1]"
       } else {
          # if there are fewer streams on card than requested change
          # the streams variable to match whats actually there
          if { $DefStreams(ul)  < $streams } {
             set streams $DefStreams(ul)
          }
      
          ############################################
          # set up a SmartBits type structure to hold#
          # card configuration data.                 #
          ############################################
          struct_new SB StreamSmartBits
          for {set j 1} {$j < $streams} {incr j} {
             ############################################
             # Get stream data for stream count $j      #
             # Do not pull Stream 0 ("hidden" stream)   #
             ############################################
             LIBCMD HTGetStructure $L3_STREAM_INFO $j 0 0 SB 0 $H $S $P
   
             puts -nonewline $output "\n Card [expr $S +1] - Stream $j of [expr $DefStreams(ul) - 1] - STATUS => "
             if { $SB(ucActive) == 1} {
                puts $output "Active"
             } else {
                puts $output "Inactive"
             }
             puts $output "-----------------------------------------------------------"
             puts $output "Layer 2 Data:"
             puts -nonewline $output "    Destination MAC ==> "
             for {set i 0} {$i < 6} {incr i} {
                puts  -nonewline $output " [format %02X $SB(ProtocolHeader.$i)]"
             }
             puts $output ""
             puts -nonewline $output "    Source MAC      ==> "
             for {set i 6} {$i < 12} {incr i} {
                puts  -nonewline $output " [format %02X $SB(ProtocolHeader.$i)]"
             }
             puts $output "\n-----------------------------------------------------------"
             puts $output "Layer 3 Data:"
             puts -nonewline $output "   Stream type is "
   
             switch $SB(ucProtocolType) {
          0 { puts $output "SmartBits"}
             2 { puts $output "IP"
                 puts -nonewline $output "    Destination IP       ==> "
                 for {set i 16} {$i < 19} {incr i} {
                    puts  -nonewline $output "[format %d  $SB(ProtocolHeader.$i)]."
                 }
                 puts $output "[format %d $SB(ProtocolHeader.19)]"   
   
                 puts -nonewline $output "    Source IP            ==> "
                 for {set i 20} {$i < 23} {incr i} {
                    puts  -nonewline $output "[format %d $SB(ProtocolHeader.$i)]."
                 }
                 puts $output "[format %d  $SB(ProtocolHeader.23)]"   
                 puts $output "\n   Frame length is $SB(uiFrameLength) bytes"
              }
           3 { puts $output "IPX"
                 puts -nonewline $output "    Dest Net ==> "
                 for {set i 16} {$i < 20} {incr i} {
                    puts  -nonewline $output "[format %02d $SB(ProtocolHeader.$i)] "
                 }
                 puts -nonewline $output " Dest Host ==> "
                 for {set i 20} {$i < 26} {incr i} {
                    puts  -nonewline $output "[format %02d $SB(ProtocolHeader.$i)] "
                 }
              puts -nonewline $output " Sckt => [format %02d $SB(ProtocolHeader.26)]"
                 puts ""
   
                 puts -nonewline $output "    Srce Net ==> "
                 for {set i 28} {$i < 32} {incr i} {
                    puts  -nonewline $output "[format %02d $SB(ProtocolHeader.$i)] "
                 }
                 puts -nonewline $output " Srce Host ==> "
                 for {set i 32} {$i < 38} {incr i} {
                    puts  -nonewline $output "[format %02d $SB(ProtocolHeader.$i)] "
                 }
              puts -nonewline $output " Sckt => [format %02d $SB(ProtocolHeader.38)]"
                 puts $output ""
             }
          4 { puts $output "UDP"
                puts -nonewline $output "    Destination IP  ==> "
                for {set i 16} {$i < 19} {incr i} {
                   puts  -nonewline $output "[format %d $SB(ProtocolHeader.$i)]."
                }
                puts "[format %d  $SB(ProtocolHeader.19)]"   
   
                puts -nonewline $output "    Source IP       ==> "
                for {set i 20} {$i < 23} {incr i} {
                   puts  -nonewline $output "[format %d $SB(ProtocolHeader.$i)]."
                }
                puts $output "[format %d  $SB(ProtocolHeader.23)]"   
                puts $output "\n   Frame length is $SB(uiFrameLength) bytes"
               }
         5 { puts $output "ARP"}
         8 { puts $output "TCP"
                puts -nonewline $output "    Destination IP  ==> "
                for {set i 16} {$i < 19} {incr i} {
                   puts  -nonewline $output "[format %d $SB(ProtocolHeader.$i)]."
                }
                puts $output "[format %d  $SB(ProtocolHeader.19)]"   
   
                puts -nonewline $output "    Source IP       ==> "
                for {set i 20} {$i < 23} {incr i} {
                   puts  -nonewline $output "[format %d $SB(ProtocolHeader.$i)]."
                }
                puts $output "[format %d $SB(ProtocolHeader.23)]"   
                puts $output "\n   Frame length is $SB(uiFrameLength) bytes"
               }
         default {puts $output "unknown"}
         
            }
        # Check ARP state - when ARP is sent time is recorded in 52 53 53 and 55
           # when reply is received the time is recorded in 56 57 58 and 59
           # all zero fields indicate an event has not happened, ie ARPStart = 0 
           # indicates ARP request was not sent, ARPEnd = 0 indicates reply was never
           # received.  Byte order on time may be system dependent
           set ARPStart 0
           set ARPStart [expr $ARPStart + $SB(ProtocolHeader.54) * 0x10000]
           set ARPStart [expr $ARPStart + $SB(ProtocolHeader.53) * 0x100]
           set ARPStart [expr $ARPStart + $SB(ProtocolHeader.52) * 1]
   
           set ARPEnd 0
           set ARPEnd [expr $ARPEnd + $SB(ProtocolHeader.58) * 0x10000]
           set ARPEnd [expr $ARPEnd + $SB(ProtocolHeader.57) * 0x100]
           set ARPEnd [expr $ARPEnd + $SB(ProtocolHeader.56) * 1]
   
        if { $ARPStart == 0 } {
                puts "   ARP requests have not been sent"
           } else {
             if { $ARPEnd == 0 } {
                        puts "   ARP requests have been sent but replies have not been received"
             } else {
                  puts "   ARP exchange complete"
                   }
           }
                
            ################################################
            # ProtocolHeader area will contain the raw data#
            ################################################
   
            puts $output "------------------------------------------------"
            puts $output "              Raw Protocol Data     "
            puts $output "------------------------------------------------"
            for {set i 0} {$i < 64} {incr i} {
               if { [expr $i % 16] == 0 } {
                  puts $output ""
                  puts -nonewline $output "[format "%02X" $i]:  "
               }
            puts  -nonewline $output " [format %02X  $SB(ProtocolHeader.$i)]"
            }
   
            puts $output ""
            if {$output == "stdout"} {
            puts "\nPress ENTER to continue"
            gets stdin response
            }
       }
     }
   
   }
     
   ######################## END show_stream #####################
   
   #####################################################################
   # set_bgfill
   # sets background (any part of packet no overlaid with stream data
   # with the Slot number +1, so the card in the hubs first slot will be filled
   # with 1 the card in the second slot with 2 and so on.
   # Uses global DATA_LENGTH
   #####################################################################
   proc set_bgfill {H S P} {
   
     struct_new filldata Int*$::DATA_LENGTH
     for {set i 0} {$i < $::DATA_LENGTH} {incr i} {
        set filldata($i.i) [expr $S + 1]
     }
     LIBCMD HTFillPattern $::DATA_LENGTH filldata $H $S $P
   }
   
   ############################################################
   ##################   MAIN PROGRAM   ########################
   ############################################################
   
   #####################################################################
   # Check for library load - is __SMARTLIB_TCL__ variable set???
   #####################################################################
   if {[info exists __SMARTLIB_TCL__] < 1} {
      # If not, look for it locally and try to load  
      if {[file exists smartlib.tcl] > 0} {
         source smartlib.tcl
      # Not loaded and not local - display message and exit
      } else {
      puts "SmartLibrary not loaded - source smartlib.tcl before starting program"
      gets stdin response
      exit
      }
   }
   
   #####################################################################
   # Check for link state, prompt for chassis IP connect if not linked
   #####################################################################
   if {[ETGetLinkStatus] < 1} {
      puts "Chassis not linked, Enter SmartBits chassis IP address"
      gets stdin ipaddr
      LIBCMD ETSocketLink $ipaddr 16385
   }
   
   # set background fill
   set_bgfill $iHub $iSlot $iPort
   
   # We use the slot numbers of iHub and iHub2 to setup the addresses.  We add
   # 1 to the slot numbers to avoid 0s in the addresses.
   ######################################################
   catch {unset streamIP}
   struct_new streamIP StreamIPVLAN
           set streamIP(ucActive) 1
           set streamIP(ucProtocolType) $STREAM_PROTOCOL_IP_VLAN
           set streamIP(uiFrameLength) $DATA_LENGTH
           set streamIP(ucTagField) 1
           set streamIP(DestinationMAC.0)  0x00
           set streamIP(DestinationMAC.1)  0x00
           set streamIP(DestinationMAC.2)  0x00
           set streamIP(DestinationMAC.3)  0x00
           set streamIP(DestinationMAC.4)  0x00
           set streamIP(DestinationMAC.5)  [expr $iSlot2 + 1] 
        set streamIP(SourceMAC.0)  0x00
           set streamIP(SourceMAC.1)  0x00
           set streamIP(SourceMAC.2)  0x00
           set streamIP(SourceMAC.3)  0x00
           set streamIP(SourceMAC.4)  0x00
           set streamIP(SourceMAC.5)  [expr $iSlot + 1] 
           set streamIP(TimeToLive) 10
           set streamIP(DestinationIP.0)  10
           set streamIP(DestinationIP.1)  [expr $iSlot2 + 1] 
           set streamIP(DestinationIP.2)  1
           set streamIP(DestinationIP.3)  10
           set streamIP(SourceIP.0)  10
           set streamIP(SourceIP.1)  [expr $iSlot + 1] 
           set streamIP(SourceIP.2)  1
           set streamIP(SourceIP.3)  10
           set streamIP(Netmask.0)  255
           set streamIP(Netmask.1)  255
           set streamIP(Netmask.2)  255
           set streamIP(Netmask.3)  0
           set streamIP(Gateway.0)  10
           set streamIP(Gateway.1)  [expr $iSlot + 1] 
           set streamIP(Gateway.2)  1
           set streamIP(Gateway.3)  1
           # VLAN parameters
           # VLAN Priority: available constants
           # VLAN_PRI_0 VLAN_PRI_1 VLAN_PRI_2 VLAN_PRI_3
           # VLAN_PRI_4 VLAN_PRI_5 VLAN_PRI_6 VLAN_PRI_7
           # VLAN_PRI_LOWEST VLAN_PRI_HIGHEST
           set streamIP(VLAN_Pri) $VLAN_PRI_0
           # VLAN CFI bit: available constants
           # VLAN_CFI_RIF_ABSENT  VLAN_CFI_RIF_PRESENT
           set streamIP(VLAN_Cfi) $VLAN_CFI_RIF_ABSENT      
           # VLAN ID                            
           set streamIP(VLAN_Vid) 0x05
   
   LIBCMD HTSetStructure $L3_DEFINE_IP_STREAM_VLAN 0 0 0 streamIP 0 $iHub $iSlot $iPort
   
   # reverse source and destination to make a mirror copy for card 2
           set streamIP(DestinationMAC.5)  [expr $iSlot + 1] 
           set streamIP(SourceMAC.5)  [expr $iSlot2 + 1] 
           set streamIP(DestinationIP.1)  [expr $iSlot + 1] 
           set streamIP(SourceIP.1)  [expr $iSlot2 + 1]  
           set streamIP(Gateway.1)  [expr $iSlot2 + 1] 
   LIBCMD HTSetStructure $L3_DEFINE_IP_STREAM_VLAN 0 0 0 streamIP 0 $iHub2 $iSlot2 $iPort2
   
   unset streamIP
   
   #####################################################################
   # Set up a structure with the fields we want to increment.  The value is the
   # amount each stream will increment by in each successive stream
   # Dest MAC will increment by 3 each time Source MAC by 2 etc
   #####################################################################
   catch {unset incrementIP}
   struct_new incrementIP StreamIPVLAN
       set incrementIP(DestinationMAC.5)  3
       set incrementIP(SourceMAC.5)  2
       set incrementIP(DestinationIP.3)  1
       set incrementIP(SourceIP.3)  1
   LIBCMD HTSetStructure $L3_DEFINE_MULTI_IP_STREAM_VLAN $SOURCE_STREAM $STREAMS2ADD 0 incrementIP 0 $iHub $iSlot $iPort
   LIBCMD HTSetStructure $L3_DEFINE_MULTI_IP_STREAM_VLAN $SOURCE_STREAM $STREAMS2ADD 0 incrementIP 0 $iHub2 $iSlot2 $iPort2
   unset incrementIP
   puts "Finished creating [expr $STREAMS2ADD +1] IP streams on cards [expr $iSlot +1] and [expr $iSlot2 +1]"
   
   display_streams $iHub $iSlot $iPort
   display_streams $iHub2 $iSlot2 $iPort2
   
   # Send ARPS from all streams configured
   LIBCMD HTSetCommand $L3_START_ARPS 0 0 0 "" $iHub $iSlot $iPort
   LIBCMD HTSetCommand $L3_START_ARPS 0 0 0 "" $iHub2 $iSlot2 $iPort2
   
   reset_capture $iHub2 $iSlot2 $iPort2
   
   # reset Counters fro both cards
   LIBCMD HTClearPort $iHub $iSlot $iPort
   LIBCMD HTClearPort $iHub2 $iSlot2 $iPort2
   
   # set transmission parameters
   LIBCMD HTTransmitMode $SINGLE_BURST_MODE $iHub $iSlot $iPort
   LIBCMD HTBurstCount $burstCount $iHub $iSlot $iPort
   LIBCMD HTRun $HTRUN  $iHub $iSlot $iPort
    
   
   puts "Counts for card [expr $iSlot + 1]"
   display_count $iHub $iSlot $iPort
   wait_for_input
   
   puts "Counts for card [expr $iSlot2 + 1]"
   display_count $iHub2 $iSlot2 $iPort2
   wait_for_input
   
   puts "Displaying packets captured on card [expr $iSlot2 + 1]"
   display_capture $iHub2 $iSlot2 $iPort2

